home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
cuj1008.zip
/
1008022A
< prev
next >
Wrap
Text File
|
1992-02-06
|
10KB
|
394 lines
///////////////////////////////////////////////////////
// Listing 2 - QC.CPP: Quadcode support routines
// by Kenneth Van Camp
///////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef __TURBOC__
#include <iostream.h>
#else
#include <stream.hpp>
#endif
#include "qc.h"
// The following macro returns the number of bytes reqd
// to store a quadcode, given the number of quits:
#define QC_NBYTES(q) (((q) - 1) / 4 + 1)
// These are shifts & masks to extract a single quit
static int QCshifts[4] = { 6, 4, 2, 0 };
static int QCmasks[4] = { 3<<6, 3<<4, 3<<2, 3 };
// This is the inverse mask:
static int QCimasks[4] =
{ 0xff^(3<<6), 0xff^(3<<4), 0xff^(3<<2), 0xff^3 };
// And these are masks for each bit in a normal byte:
static int bitmasks[8] =
{ 1, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7 };
#ifndef STAT_QC
void QuadCode::FreeMem (void)
// Free dynamic memory.
{
if (nquits > 0 && qca)
delete qca;
qca = NULL;
nquits = 0;
} // QuadCode::FreeMem
#endif // STAT_QC
QuadCode::QuadCode (COORD i, COORD j, int nq)
// QuadCode constructor from (I,J) coordinates of the
// upper-left corner of the qc.
// i is the vertical row# of quadcode (0 at top)
// j is the horizontal column# of quadcode
// nq is the # of quits in quadcode
{
#ifndef STAT_QC
qca = NULL;
#endif
nquits = 0;
assert (nq > 0 && nq <= MAXQUITS);
// We traverse both the (i,j) coordinates and the qc
// from the msb to the lsb and msq to msq. Note the
// following assumes MAXQUITS is a multiple of 8.
#ifdef MSB_FIRST
BYTE *ip = (BYTE *)&i + (MAXQUITS - nq) / 8;
BYTE *jp = (BYTE *)&j + (MAXQUITS - nq) / 8;
#else
BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1 -
(MAXQUITS - nq) / 8;
BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1 -
(MAXQUITS - nq) / 8;
#endif
int bit = 7 - (MAXQUITS - nq) % 8;
int nbytes = QC_NBYTES (nq);
#ifndef STAT_QC
qca = new BYTE [nbytes];
assert (qca != NULL);
#endif
memset (qca, '\0', nbytes);
BYTE *p = qca;
nquits = nq;
int pos = 0; // position within qc (0,1,2,3)
for ( ; nq > 0; nq--)
{
if (*ip & bitmasks[bit])
*p |= 1 << (QCshifts[pos] + 1);
if (*jp & bitmasks[bit])
*p |= 1 << QCshifts[pos];
// Advance to next quit
if (++pos > 3)
{
pos = 0;
p++;
}
// Back up to next bit
if (--bit < 0)
{
bit = 7;
#ifdef MSB_FIRST
ip++; jp++;
#else
ip--; jp--;
#endif
} // if --bit
} // for nq
} // QuadCode::QuadCode
void QuadCode::Init (const char *chqc)
// QuadCode initializer from string.
// chqc is the quadcode in a null-terminated
// character representation - i.e., "123"
{
int nq = strlen (chqc);
#ifndef STAT_QC
qca = NULL;
#endif
nquits = 0;
assert (nq > 0 && nq <= MAXQUITS);
size_t nbytes = QC_NBYTES (nq);
#ifndef STAT_QC
qca = new BYTE [nbytes];
assert (qca != NULL);
#endif
memset (qca, '\0', nbytes);
// Store quadcode in binary form, from msq to lsq.
int i;
int pos; // pos within byte of this quit (0,1,2,3)
BYTE *p; // ptr to current byte in qc
for (i = 0, pos = 0, p = qca; i < nq; i++)
{
int val = chqc[i] - '0';
assert (val >= 0 && val <= 3);
*p |= val << QCshifts[pos];
if (++pos > 3)
{
pos = 0;
p++;
}
} // for i
nquits = nq;
} // QuadCode::Init
int QuadCode::GetQuit (int quit)
// Return single quit from quadcode.
// quit is the pos# of the quit to extract (zero-based).
// Pos 0 is the high-order quit ('1' in "123").
{
assert (quit <= nquits && quit >= 0);
int byte = quit / 4;
int pos = quit % 4;
return ( (*(qca + byte) & QCmasks[pos]) >>
QCshifts[pos]);
} // QuadCode::GetQuit
void QuadCode::SetQuit (int quit, int val)
// Set value of a single quit.
// quit is the pos# of the quit to extract (zero-based).
// val is the value of the quit (0, 1, 2 or 3).
{
assert (quit <= nquits && quit >= 0 && val >= 0 &&
val < 4);
BYTE *p = qca + quit / 4;
int pos = quit % 4;
// Clear out the old value
*p &= (255 - QCmasks[pos]);
// Put in the new value
*p |= val << QCshifts[pos];
} // QuadCode::SetQuit
void QuadCode::ToIJ (COORD &i, COORD &j, int &nq)
// Convert quadcode value to (I,J).
// The offsets returned are the coords of the
// upper-left corner of the quadcode.
// i is the row#
// j is the col#
// nq is the #quits
{
i = j = nq = 0;
if (nquits < 1)
return;
assert (nquits <= MAXQUITS);
nq = nquits;
// Go from lsq to msq. Following loop is based on the
// conversion algorithm by Gargantini:
#ifdef MSB_FIRST
BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1;
BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1;
#else
BYTE *ip = (BYTE *)&i;
BYTE *jp = (BYTE *)&j;
#endif
int quit, // current quit# in qc
bit = 0; // current bit# in byte of (i,j)
for (quit = nquits-1; quit >= 0; quit--)
{
int val = GetQuit (quit);
// Bit pos 0 gives J val, bit pos 1 gives I val.
int ival = val >> 1;
int jval = val & 1;
*ip |= (ival << bit);
*jp |= (jval << bit);
// Advance to next bit
if (bit == 7)
{
bit = 0;
#ifdef MSB_FIRST
ip--; jp--;
#else
ip++; jp++;
#endif
}
else
bit++;
} // for quit
} // QuadCode::ToIJ
int QuadCode::Compare (QuadCode &qc)
// Compare one quadcode to another.
// Return 0 if the two quadcodes are equal; -1 if the
// current quadcode is less than qc; or +1 if the
// current quadcode is greater than qc.
// qc is the quadcode to compare to
{
// Check for zero-length quadcodes
if (nquits == 0)
{
if (qc.nquits == 0)
return 0;
else
return -1;
}
else if (qc.nquits == 0)
return 1;
BYTE *p1 = qca;
BYTE *p2 = qc.qca;
BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
BYTE *end2 = p2 + QC_NBYTES (qc.nquits) - 1;
// Compare each byte of the two quadcodes.
for ( ; p1 <= end1 && p2 <= end2; p1++, p2++)
if (*p1 != *p2)
{
if (*p1 < *p2)
return -1;
else
return 1;
}
if (nquits == qc.nquits)
// quadcodes same
return 0;
else if (nquits < qc.nquits)
// this quadcode contains qc
return -1;
else
// qc contains this quadcode
return 1;
} // QuadCode::Compare
int QuadCode::Sibling (const QuadCode *qc)
// Compare one quadcode to another.
// Return TRUE if they are siblings, FALSE if not.
// qc is the quadcode to compare to
{
// Must be the same length, can't be empty.
if (qc == NULL || nquits != qc->nquits || nquits==0)
return (FALSE);
BYTE *p1 = qca;
BYTE *p2 = qc->qca;
BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
// Compare each byte of the two quadcodes.
// If any differ except the last, then not siblings.
for ( ; p1 < end1; p1++, p2++)
if (*p1 != *p2)
return (FALSE);
if (*p1 == *p2)
// Quadcodes are same
return (FALSE);
// Make sure final byte matches in all but last quit.
int pos = (nquits-1) % 4;
return
((*p1 & QCimasks[pos]) == (*p2 & QCimasks[pos]));
} // QuadCode::Sibling
int QuadCode::Contains (QuadCode &qc)
// Compare one quadcode to another.
// Return TRUE if the current quadcode contains qc
// (i.e., is equal to it or is a parent of it), or
// FALSE otherwise.
// qc is the quadcode to compare to
{
if (nquits > qc.nquits)
return (FALSE);
if (nquits == 0)
return (TRUE);
BYTE *p1 = qca;
BYTE *p2 = qc.qca;
BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
BYTE *end2 = p2 + QC_NBYTES (qc.nquits) - 1;
// Compare each byte of the two quadcodes.
for ( ; p1 <= end1 && p2 <= end2; p1++, p2++)
if (*p1 != *p2)
{
// Found a byte that differs. This quadcode
// contains qc iff: (1) We are at the last byte
// of this quadcode; and (2) All quits in this
// quadcode before the last one match the
// corresponding quits in qc.
if (p1 != end1)
return (FALSE);
int lastpos = (nquits - 1) % 4;
int pos;
for (pos = lastpos; pos >= 0; pos--)
if ((*p1 & QCmasks[pos]) !=
(*p2 & QCmasks[pos]))
return (FALSE);
// They match up to nquits.
return (TRUE);
}
// All bytes match - either qc's are same or this is
// the parent.
return (TRUE);
} // QuadCode::Contains
void QuadCode::MakeParent (void)
// Make quadcode into its parent.
{
// Clear the bits that saved the last quit. Don't
// bother to reclaim storage if size is reduced.
nquits--;
int byte = nquits / 4;
int pos = nquits % 4;
*(qca + byte) &= QCimasks[pos];
} // QuadCode::MakeParent
QuadCode &QuadCode::operator= (QuadCode &qc)
// Assign one quadcode the same value as another.
// The target quadcode is assumed to be initialized.
// qc is the quadcode to copy
{
#ifdef STAT_QC
memcpy (qca, qc.qca, NBYTE_QC);
#else
FreeMem();
size_t nbytes = QC_NBYTES (qc.nquits);
qca = new BYTE [nbytes];
assert (qca != NULL);
memcpy (qca, qc.qca, nbytes);
#endif // STAT_QC
nquits = qc.nquits;
return (*this);
} // QuadCode::operator=
ostream &operator<< (ostream &stream, QuadCode &qc)
// Overload "Put to" operator for output to stream.
// stream is the stream to print to
// qc is the quadcode to print
{
int quit;
for (quit = 0; quit < qc.nquits; quit++)
stream << (char)(qc.GetQuit (quit) + '0');
return (stream);
} // operator<<
istream &operator>> (istream &stream, QuadCode &qc)
// Overload "Get From" operator for input from stream.
// stream is the stream to get from
// qc is the quadcode to store the result in
{
char tmp[80];
qc.FreeMem();
stream >> tmp;
qc.Init (tmp);
return (stream);
} // operator>>